package com.github.tetrisgame.manager;

import android.os.Handler;
import android.os.Looper;

import com.github.tetrisgame.model.Block;
import com.github.tetrisgame.model.GridModel;
import com.github.tetrisgame.ui.view.GameView;
import com.github.tetrisgame.ui.view.PreviewView;
import com.github.tetrisgame.utils.Constants;

import java.util.Timer;
import java.util.TimerTask;

/*
如果一个类在程序中只有一个对象
就可以使用单例设计模式
 */
public class GameCenter {
    //内部提供一个静态共享的属性对象
    public static final GameCenter defaultCenter = new GameCenter();

    private PreviewView mPreviewView;
    private GameView mGameView;
    private int row = Constants.ROW;
    private int column = Constants.COLUMN;
    public GridModel[][] boards;
    private Timer mTimer; //定时器
    private int mNormalSpeed = 800;
    private int mFastSpeed = 20;
    private boolean mIsNormalSpeed = true;
    private OnGameOverListener mGameOverListener;
    private OnGameScoreChangeListener mScoreChangeListener;
    private long mTotalScore;
    private int level = 1;
    private OnGameLevelChangeListener mLevelChangeListener;

    public void setBoardSize(int row, int column){
        this.row = row;
        this.column = column;
        this.boards = new GridModel[row][column];
        BlockManager.defaultManager.resetPosition(row,column);
        mGameView.refresh();
    }

    //构造方法私有化
    //不让外部直接创建当前类的对象
    private GameCenter(){}

    //让GameCenter绑定预览和游戏视图对象
    public void bindView(PreviewView previewView, GameView gameView) {
        mPreviewView = previewView;
        mGameView = gameView;
    }

    //开始游戏
    public void start() {
        mIsNormalSpeed = true;
        resetTimer(true);
    }

    //暂停游戏
    public void stop() {
        if (mTimer != null) mTimer.cancel();
    }

    //清楚内容
    public void restart(){
        //重新创建新的数组对象
        boards = new GridModel[row][column];
        //开始游戏
        start();
    }

    //重置定时器
    private void resetTimer(boolean isNormal){
        if (mTimer != null) mTimer.cancel();

        //开启新的定时器
        mTimer = new Timer();
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                moveDown();
            }
        },0,isNormal ? mNormalSpeed : mFastSpeed);
    }

    //游戏初始化
    public void initGame(){
        showNext();
    }

    //左移
    public void moveLeft() {
        //将方块中的column-1
        BlockManager.defaultManager.getCurrentBlock().reduceColumn();
        if (isCollision()){
            BlockManager.defaultManager.getCurrentBlock().addColumn();
        }
        //刷新界面
        mGameView.refresh();
    }
    //右移
    public void moveRight() {
        //将方块中的column+1
        BlockManager.defaultManager.getCurrentBlock().addColumn();
        if (isCollision()){
            BlockManager.defaultManager.getCurrentBlock().reduceColumn();
        }
        //刷新界面
        mGameView.refresh();
    }
    //快速下落
    public void dropDown(){
        mIsNormalSpeed = false;
        resetTimer(false);
    }

    //下移
    public void moveDown() {
        //将方块中的row+1
        BlockManager.defaultManager.getCurrentBlock().addRow();

        if (isCollision()){
            BlockManager.defaultManager.getCurrentBlock().reduceRow();
            //将当前这个方块合并到面板数组中
            mergeBlock();
            //消除满行的数据
            clearLines();
            if (checkGameOver()){
                //关闭定时器
                if (mTimer != null) mTimer.cancel();

                //游戏结束
                if (mGameOverListener != null){
                    new Handler(Looper.getMainLooper()).post(()->{
                        mGameOverListener.onGameOver();
                    });

                }
                return;
            }
            //显示下一个
            showNext();
            //检测游戏是否结束
            //切换定时器
            if (!mIsNormalSpeed){
                mIsNormalSpeed = true;
                resetTimer(true);
            }
        }

        //刷新界面
        mGameView.refresh();
    }

    //判断游戏是否结束
    private boolean checkGameOver() {
        GridModel[] models = boards[0];
        for (int i = 0; i < column; i++) {
            if (models[i] != null){
                return true;
            }
        }

        return false;
    }

    //消行
    private void clearLines(){
        int totalLines = 0;
        //从boards最底层开始判断
        for (int i = row-1; i >= 0; i--) {
            //获取最后一行的数据
            GridModel[] linesModel = boards[i];
            boolean isFull = true;
            for (int j = 0; j < column; j++) {
                if (linesModel[j] == null){
                    isFull = false;
                    break;
                }
            }
            if (isFull){ //i对应的这一行满了
                for (int j = i-1; j >= 0; j--) {
                    //将j-1的内容拷贝到j行
                    System.arraycopy(boards[j],0,boards[j+1],0,column);
                }
                totalLines ++;
                //继续从当前这一行判断
                i++;
            }
        }

        if (totalLines > 0){
            mTotalScore += totalLines * 100;
            //level和分数的关系
            if (mTotalScore % 100 == 0){
                level ++;
                if (mLevelChangeListener != null){
                    new Handler(Looper.getMainLooper()).post(()->{
                        mLevelChangeListener.levelChanged(level);
                    });
                }
                mNormalSpeed -= 100;

                if (mNormalSpeed <= 0) mNormalSpeed = 10;
                resetTimer(true);
            }
            if (mScoreChangeListener != null){
                new Handler(Looper.getMainLooper()).post(()->{
                    mScoreChangeListener.scoreChanged(mTotalScore);
                });
            }
        }
    }

    private void showNext(){
        //获取预览方块对象  默认方块出现的位置是在最顶部 row=0 的中心位置 column = column/2-1
        Block previewBlock = BlockManager.defaultManager.getPreviewBlock(0,column/2-1);
        //给预览视图显示
        mPreviewView.showBlock(previewBlock);
        //刷新界面
        mGameView.refresh();
    }

    //将当前这个方块合并到面板数组中
    private void mergeBlock(){
        Block block = BlockManager.defaultManager.getCurrentBlock();
        int[][] shapes = block.getShape();
        int x;
        int y;
        for (int i = 0; i < shapes.length; i++) {
            for (int j = 0; j < shapes[0].length; j++) {
                if (shapes[i][j] == 1){
                    x = block.column + j;
                    y = block.row + i;
                    boards[y][x] = new GridModel(block.imageResource);
                }
            }
        }
    }

    //变换图形
    public void rotate() {
        BlockManager.defaultManager.getCurrentBlock().rotate();
        if (isCollision()){
            for (int i = 0; i < 3; i++) {
                BlockManager.defaultManager.getCurrentBlock().rotate();
            }
        }
        //刷新界面
        mGameView.refresh();
    }

    //判断是否碰撞了
    //边界（上下右边界）
    //碰到方块
    private boolean isCollision(){
        Block block = BlockManager.defaultManager.getCurrentBlock();
        int[][] shapes = block.getShape();
        for (int i = 0; i < shapes.length; i++) {
            for (int j = 0; j < shapes[0].length; j++) {
                if (shapes[i][j] == 1){

                    if (block.column+j < 0) return  true;
                    if (block.column + j >= column) return  true;
                    if (block.row + i >= row) return  true;

                    GridModel model = boards[block.row+i][block.column+j];
                    if (model != null) return true;
                }
            }
        }
        return false;
    }

    public void setOnGameOverListener(OnGameOverListener listener){
        this.mGameOverListener = listener;
    }
    public void setOnScoreChangeListener(OnGameScoreChangeListener listener){
        this.mScoreChangeListener = listener;
    }
    public void setOnLevelChangeListener(OnGameLevelChangeListener listener){
        this.mLevelChangeListener = listener;
    }

    public interface OnGameOverListener{
        void onGameOver();
    }
    public interface OnGameScoreChangeListener{
        void scoreChanged(long score);
    }
    public interface OnGameLevelChangeListener{
        void levelChanged(int level);
    }
}
